using System;
using System.Collections.Generic;
using System.Reflection;
using NFreeMarker.Template;

namespace NFreeMarker.Ext.Beans
{
    class MethodMap
    {
        private readonly string _name;
        private readonly BeansWrapper _wrapper;
        private readonly OverloadedMethod _fixArgMethod = new OverloadedFixArgMethod();
        private OverloadedMethod _varArgMethod;

        internal MethodMap(string name, BeansWrapper wrapper)
        {
            _name = name;
            _wrapper = wrapper;
        }
        
        internal BeansWrapper GetWrapper()
        {
            return _wrapper;
        }

        internal void AddMember(MemberInfo member)
        {
            _fixArgMethod.AddMember(member);
            if (MethodUtilities.IsVarArgs(member))
            {
                if (_varArgMethod == null)
                {
                    _varArgMethod = new OverloadedVarArgMethod();
                }
                _varArgMethod.AddMember(member);
            }
        }

        internal MemberAndArguments GetMemberAndArguments(IList<ITemplateModel> arguments)
        {
            object memberAndArguments = _fixArgMethod.GetMemberAndArguments(arguments, _wrapper);
            if (memberAndArguments == OverloadedMethod.NoSuchMethod)
            {
                if (_varArgMethod != null)
                {
                    memberAndArguments = _varArgMethod.GetMemberAndArguments(arguments, _wrapper);
                }
                if (memberAndArguments == OverloadedMethod.NoSuchMethod)
                {
                    throw new TemplateModelException("No signature of method " +
                            _name + " matches the arguments");
                }
            }
            if (memberAndArguments == OverloadedMethod.AmbiguousMethod)
            {
                throw new TemplateModelException("Multiple signatures of method " +
                        _name + " match the arguments");
            }
            return (MemberAndArguments)memberAndArguments;
        }
    }
}